﻿using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;
using GiveAQuiz.Data;
using System.Web.Security;
using System.ServiceModel;
using System.Linq.Expressions;
using System.Collections;

namespace GiveAQuizSite.Services
{
#if DEBUG
  [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
#endif
  public class QuizDataService : DataService<GiveAQuizEntities>
  {
    // This method is called only once to initialize service-wide policies.
    public static void InitializeService(DataServiceConfiguration config)
    {
      // Configure the necessary access for Creating Quizzes
      config.SetEntitySetAccessRule("QuizDefinitions", EntitySetRights.ReadSingle| 
                                                        EntitySetRights.WriteAppend | 
                                                        EntitySetRights.WriteReplace);
      config.SetEntitySetAccessRule("QuestionDefinitions", EntitySetRights.All);

      // Grant Access for Taking Tests (Requires Anonymous access)
      config.SetEntitySetAccessRule("Quizzes", EntitySetRights.ReadSingle);
      config.SetEntitySetAccessRule("QuizTakers", EntitySetRights.WriteAppend);
      config.SetEntitySetAccessRule("QuizResults", EntitySetRights.WriteAppend);
      config.SetEntitySetAccessRule("QuizAnswers", EntitySetRights.WriteAppend);

      // Allow readonly access to retrieve data from the service operation.
      config.SetServiceOperationAccessRule("CanTakeQuiz", ServiceOperationRights.AllRead);

      config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;

  #if DEBUG
      config.UseVerboseErrors = true;
  #endif
    }

    protected override void OnStartProcessingRequest(ProcessRequestArgs args)
    {
      base.OnStartProcessingRequest(args);

//        throw new DataServiceException("Cannot call the Data Service from outside the Silverlight client.");

    }

    [ChangeInterceptor("QuestionDefinitions")]
    public void OnQuestionDefinitionSave(QuestionDefinition question, UpdateOperations operation)
    {
      if (!HttpContext.Current.Request.IsAuthenticated)
      {
        throw new DataServiceException("Cannot update/change Questions unless logged in.");
      }

      if (operation == UpdateOperations.Change ||
          operation == UpdateOperations.Delete)
      {
        if (question.QuizDefinition.Owner != GetOwner())
        {
          throw new DataServiceException("Cannot update or delete QuestionDefinitions that you do not own.");
        }
      }
    }

    [ChangeInterceptor("QuizDefinitions")]
    public void OnQuizDefinitionSave(QuizDefinition quiz, UpdateOperations operation)
    {
      if (!HttpContext.Current.Request.IsAuthenticated)
      {
        throw new DataServiceException("Cannot update/change QuizDefinitions unless logged in.");
      }

      // If Adding a QuizDefinition, set the owner to the current user
      if (operation == UpdateOperations.Add)
      {
        quiz.Owner = GetOwner();
      }
      else
      {
        if (quiz.Owner != GetOwner())
        {
          throw new DataServiceException("Cannot update or delete QuizDefinitions that you do not own.");
        }
      }
    }

    [QueryInterceptor("QuizDefinitions")]
    public Expression<Func<QuizDefinition, bool>> OnQuizDefinitionQuery()
    {
      //// Only allow if the request fo the call came from our website
      //if (!HttpContext.Current.Request.Headers["Host"].Contains(
      //      HttpContext.Current.Request.Url.GetComponents(
      //        UriComponents.Host, UriFormat.Unescaped)))
      //{
      //  throw new DataServiceException("Cannot call from outside our domain");
      //}

      // returning a true means we aren't limiting the query
      return b => true;
    }

    [WebGet]
    public bool CanTakeQuiz(int quizId, string email)
    {
      return this.CurrentDataSource.QuizTakers.Where(t => t.EMail == email &&
                                                     t.QuizResults.Any(r => r.Quiz.Id == quizId)).Count() == 0;
    }

    // Retrives the current Guid of the Forms Authentication Owner
    Guid GetOwner()
    {
      var user = Membership.GetUser();
      if (user != null)
      {
        return (Guid)user.ProviderUserKey;
      }
      else
      {
        throw new DataServiceException("This operation cannot be performed without logging in.");
      }

    }


  }
}
